#include "net_protocol_update.h"
#include "global_protocol_update.h"
#include "eth_app_network.h"
#include "global.h"
#include "app_update_send_que.h"

/*
	通过网络协议下载固件包的程序
	设备最长应答67
*/

static void request_update_pack_send(uint16_t  pack_index);
static uint8_t protocol_lot_update_process(uint8_t *pcmd,uint16_t _length);
static uint8_t request_update_pack_ack(uint8_t *pack,uint16_t _length);
static uint8_t get_soft_version(uint8_t * pack,uint16_t _length);;
static uint8_t New_version_notification(uint8_t *ppack,uint16_t _length);
static uint8_t deal_update(uint8_t * pack,uint16_t _length); //执行升级
static uint16_t SetUpdatePacket(uint8_t _command,uint16_t _dataLength,  const uint8_t* _pInputDataBuf, uint8_t* _pOutputDataBuf);
static uint8_t protocol_update_check( unsigned char *unpack_data,uint16_t unpack_length);
uint8_t curr_update_dev_type=0;
#define data_send(buff,len)	fixlen_que_Wr(&g_app_UPDATE_SEND_QUE.g_que,buff,len);
static uint16_t step = 0;
static uint16_t count = 0;
static uint16_t data_length = 0;
uint16_t recv_data_one_by_one(uint8_t data)
{

#ifdef PRINT_DATA
    printf("%02X", data);
#endif

    if (step == 0 && data == 0xfe) //接收到包头
    {
        protocol_update_buff[step] = data;
        ++step;
    }
    else if (step == 1)                //接收到指令
    {
        protocol_update_buff[step] = data;
        ++step;
    }
    else if (step == 2 ||step == 3)              //接收到length（数据长度）
    {
        protocol_update_buff[step] = data;
        ++count;
        ++step;
        if (count == 2)
        {
            count = 0;
            data_length = u8_2_u16(&protocol_update_buff[2]);
            if(data_length >PROTOCOL_UPDATE_BUFF_SIZE)
            {
                //printf("----> data_length too long %d\n",data_length);
                step=0;
                count = 0;
                return step;
            }
//              if(len==0)  //处理无真实数据体的包
//                  i=5;
        }
    }
    else if ((step >= 4) && (data_length > 0))
    {
        data_length--;
        protocol_update_buff[step++] = data;
    }
    else if (step >= 4)
    {
        protocol_update_buff[step] = data;
        ++count;
        ++step;
        if (count >= 2)
        {
            /*********  输出接收到的数据        ********/
//          for(int j=0;j<i;j++){
//              printf("tmp: %x ",tmp[i]);
//          }
            protocol_update_check(protocol_update_buff, step);        //传入蓝牙数据包
            count = 0;
            step = 0;
        }

    }
    else
    {
        step = 0;
        count = 0;
        data_length = 0;
				//printf("丢弃\n");
    }

    return step;
}

static void protocol_package_reset()
{
    step = 0;
    count = 0;
    data_length = 0;
}
typedef struct
{
    unsigned short cmd;
    uint8_t (*handler)(uint8_t * ppack,uint16_t length);
} rst_cmd_handler;

static uint8_t get_soft_version(uint8_t *pack, uint16_t _length)
{
    uint8_t sendbuff[25] = {0};
    uint8_t ack_pack[35];
    uint16_t pos,len;

    printf("needs to get the current ver\n");
    sendbuff[pos++] = 0;

    strcpy(&sendbuff[pos], SOFTWARE_VER);
    pos+=10;

    strcpy(&sendbuff[pos], HARDWARE_VER);
    pos+=10;

    sendbuff[pos++] = DEVICE_TYPE;

    uint16_t addr=ef_get_env_int("device_id");
    sendbuff[pos++] = (uint8_t)(addr>>8);
    sendbuff[pos++] = (uint8_t)(addr);
		
    len = SetUpdatePacket(GET_SOFT_VERSION,pos, sendbuff, ack_pack);
    data_send(ack_pack, len);
    return 0;
}

static const rst_cmd_handler  cmd_handler[] =
{
    {GET_SOFT_VERSION, &get_soft_version},
    {NEW_VERSION_NOTIFICATION,&New_version_notification},
    {REQUEST_UPDATE_PACKAGE,&request_update_pack_ack},
    {DEAL_UPDATE,&deal_update},
};


static uint8_t protocol_update_check( unsigned char *unpack_data,uint16_t unpack_length)
{
    uint16_t crc = (protocol_update_buff[unpack_length-2]<<8 | protocol_update_buff[unpack_length-1]);
    uint16_t cmd;
    uint16_t data_length = (uint16_t)(protocol_update_buff[2]<<8 | protocol_update_buff[3]);
    uint16_t cal_crc16 = get_crc(unpack_data+1,3+data_length);

    if(crc != cal_crc16)
    {
        printf("<---crc error :get crc16 %x   -    cal the crc16 = %x",crc,cal_crc16);
        return 1;
    }
    for(int i=0; i<sizeof(cmd_handler)/sizeof(rst_cmd_handler); i++)
    {
        cmd =unpack_data[1];
        if(cmd == cmd_handler[i].cmd)
        {
            if(cmd_handler[i].handler == NULL)     //????????
                return 1;
            cmd_handler[i].handler(unpack_data,unpack_length);
            return 0;
        }
    }

    return 0;
}
static uint16_t SetUpdatePacket(uint8_t _command,uint16_t _dataLength,const uint8_t* _pInputDataBuf,uint8_t* _pOutputDataBuf)
{
    uint8_t cnt=0;
    _pOutputDataBuf[cnt++] = 0xFE;
    _pOutputDataBuf[cnt++] = _command;
    _pOutputDataBuf[cnt++] = _dataLength >> 8;
    _pOutputDataBuf[cnt++] = _dataLength;

    memcpy(&_pOutputDataBuf[cnt],_pInputDataBuf,_dataLength);
    cnt = cnt+_dataLength;
    uint16_t crc16 = get_crc(_pOutputDataBuf+1,3+_dataLength);
    _pOutputDataBuf[cnt++] = crc16 >>8;
    _pOutputDataBuf[cnt++] = crc16 ;
    return cnt;
}





static uint16_t g_check_value =0; //TODO：
static UpdataHead updata_pack= {0}; //升级配置

static void request_update_pack_send(uint16_t  pack_index);

/**** 超时重发机制 ************/
#define MAX_RE_TIMES 10
#define RE_TIME_COUNT 2*1000 //10s 
static uint8_t  re_send_start_flag = 0;
static uint32_t re_time_count = 0;
static uint8_t  re_times = 0;

static uint8_t wait_update_deal_flag = 0;
static uint32_t wait_update_deal_times = 0 ; //10s
void start_re_send_timer()
{
    re_send_start_flag = 1;
//    re_time_count = 0;
//    re_times = 0;
}
void stop_re_send_timer()
{
		re_send_start_flag = 0;
    re_time_count = 0;
    re_times = 0;
}
void protocol_lot_re_send_requset_deal(uint16_t div_factor)//输入调用分频
{
    if (re_send_start_flag == 1)
    {
        re_time_count++;
        if (re_time_count > RE_TIME_COUNT / div_factor)
        {

            re_times ++;//重发次数
            if (re_times > MAX_RE_TIMES)
            {
								//printf("超出\n");
                re_time_count = 0;
                re_times = 0;
                re_send_start_flag = 0;
                ef_set_env("is_updating", "0");
            }
            else
            {
                re_time_count = 0;
                printf("%d re_send_requeset pack !!!!!!!!!! \n",re_times);
                request_update_pack_send(updata_pack.cur_packet_index);
            }
        }
    }
}
static uint8_t New_version_notification(uint8_t *pack,uint16_t _length)
{
    uint8_t ack_pack[50];
    char recv_soft_ver[10];
    char recv_hard_ver[10];
    uint16_t dataLength;
    uint8_t ack;
    uint8_t result[2]= {0};
    update_check();

    strcpy(recv_soft_ver,&pack[6]);
    strcpy(recv_hard_ver,&pack[16]);
    curr_update_dev_type=pack[26];

    if(curr_update_dev_type==DEVICE_TYPE) {			//检查设备类型 如果是网关就升级自己 否则保存固件包 作为自设备固件
        printf("gateway update\n");
        if(strcmp(recv_soft_ver,SOFTWARE_VER) == 0)
        {
            result[1] = VER_ALREADY_NEW;
            printf("the new version the same as the current version!. \n");
            goto __exit;
        }
        else
        {
            uint16_t addr = u8_2_u16(&pack[27]);		//接收子设备固件 不用管地址，子设备升级过程中自己会获取
#ifndef UPDATE_TEST
            if(strcmp(&pack[16],HARDWARE_VER)==0&&addr==ef_get_env_int("device_id")) {
#endif
                memcpy(updata_pack.new_soft_ver,pack+4,strlen(SOFTWARE_VER));
                printf("the NEW version(%s) is different from current version(%s). \n",recv_soft_ver,SOFTWARE_VER);
#ifndef UPDATE_TEST
            }
            else
            {
                result[1] =UPDATE_ERROR;
                printf("ERR recv hardware or device addr (%s %d)\n",recv_hard_ver,addr);
                printf("ERR self hardware or device addr (%s %d)\n",HARDWARE_VER,ef_get_env_int("device_id"));
                goto __exit;
            }
#endif
        }


    } else {
        memcpy(updata_pack.new_soft_ver,pack+4,strlen(SOFTWARE_VER));
        printf("subset update\n");

    }


    if(updata_pack.MD2[0]== pack[33] &&updata_pack.MD2[1] == pack[34] \
            && updata_pack.one_packet_length ==(uint16_t)(pack[29]<<8)+pack[30]\
            && updata_pack.all_packet_num == (uint16_t)(pack[31]<<8)+pack[32]) //????????
    {
        printf("---> continue transferring from breakpoint, index pack %d .\n",updata_pack.cur_packet_index);
    }
    else
    {
        printf("---> start update ----------->\n");
        updata_pack.cur_packet_index = 0;

        updata_pack.one_packet_length=(uint16_t)(pack[29]<<8)+pack[30];
        updata_pack.all_packet_num   =(uint16_t)(pack[31]<<8)+pack[32];
        updata_pack.MD2[0]=pack[33];
        updata_pack.MD2[1]=pack[34];
        updata_pack.cur_write_size = 0;
        g_check_value = 0;
        if(curr_update_dev_type==DEVICE_TYPE) {

            update_start(updata_pack.all_packet_num * updata_pack.one_packet_length);
        }
        else {
            ef_set_env("subset_soft_ver",recv_soft_ver);
            ef_set_env("subset_hard_ver",recv_hard_ver);
            ef_set_env_int("subset_bin_size",updata_pack.all_packet_num * updata_pack.one_packet_length);
            ef_set_env_int("subset_dev_type",curr_update_dev_type);
            update_start_subset(updata_pack.all_packet_num * updata_pack.one_packet_length);
        }
    }
    printf("--->one pack length is %d----------->\n",updata_pack.one_packet_length);
    printf("--->total num is %d----------->\n",updata_pack.all_packet_num);
    printf("--->MD2  %d ,  %d----------->\n",updata_pack.MD2[0],updata_pack.MD2[1]);
    if(updata_pack.one_packet_length * updata_pack.all_packet_num >= FLASH_SPACE_MAX)
    {
        result[1] = FLASH_NOT_ENOUGH; //run out of memory
        printf("--->run out of flash, flash max: %d K -----------> \n",FLASH_SPACE_MAX/1024);
        goto __exit;
    }

__exit:

    uint16_t length_tmp = SetUpdatePacket(NEW_VERSION_NOTIFICATION,2,&result[0],ack_pack);
    data_send((uint8_t *)ack_pack,length_tmp);

    if(result[1] == 0)
    {
        //init_re_send_timer();
        request_update_pack_send(updata_pack.cur_packet_index);
    }
    return result[1];
}

static void request_update_pack_send(uint16_t  pack_index)
{
    start_re_send_timer();//开始计时

    uint16_t length_tmp;
    int pos=0;
    uint8_t sendBuf[18] = {0};
    uint8_t ack_pack[50];
    strcpy(sendBuf,updata_pack.new_soft_ver);
    pos+=10;
    sendBuf[pos++] = (uint8_t)(pack_index>>8);
    sendBuf[pos++] = (uint8_t)pack_index;
    printf("requset pack index: %d \n", pack_index);
    length_tmp = SetUpdatePacket(REQUEST_UPDATE_PACKAGE,pos,sendBuf,ack_pack);
    data_send((uint8_t *)ack_pack,length_tmp);
}
static uint8_t upload_update_pack_down_status(uint8_t status)
{
    printf("upload_update_pack_down_status: %d \n", status);
    uint16_t length_tmp;
    uint8_t  sendBuf = 0;
    uint8_t ack_pack[20];
    length_tmp = SetUpdatePacket(UPLOAD_UPDATE_PACK_DOWN_STATUS,1,&sendBuf,ack_pack);
    data_send((uint8_t *)ack_pack,length_tmp);
}
static uint8_t request_update_pack_ack(uint8_t *pack,uint16_t _length)
{
    int ret = -1;
    printf("received a blue update pack \n");
    uint16_t updata_pack_length;
    if(pack[4]==0)
    {
//#ifndef UPDATE_TEST
        if(updata_pack.one_packet_length==(_length-9)||updata_pack.cur_packet_index == (updata_pack.all_packet_num-1))
        {
//#endif
            if(updata_pack.cur_packet_index==((uint16_t)(pack[5]<<8)+pack[6]))//查看是否自己请求的包
            {
                printf("receviced pack ack,index:%d \n",updata_pack.cur_packet_index);
                updata_pack_length = 	((uint16_t)(pack[2] <<8 | pack[3] ))-3;

                stop_re_send_timer();
                __disable_irq();	//关中断
                if(!update_write(pack+4+3,updata_pack_length,(size_t *)&updata_pack.cur_write_size,updata_pack.all_packet_num*updata_pack.one_packet_length))
                {
                    //printf(">>>> write OK\n");
                    g_check_value = check_bin(g_check_value,pack+4+3,updata_pack_length);
                    printf("write OK pack len:%d , cur write size %d ,total size %d\n",updata_pack_length,updata_pack.cur_write_size,updata_pack.all_packet_num*updata_pack.one_packet_length);
                }
                else
                {
                    //printf(">>>> write ERR\n");
                    printf("write ERR request:%d \n",updata_pack.cur_packet_index);
                    request_update_pack_send(updata_pack.cur_packet_index);
                    __enable_irq();	//开中断();
                    return 1;
                }
                __enable_irq();	//开中断();
                if(updata_pack.cur_packet_index ==(updata_pack.all_packet_num-1))
                {
                    printf("update pack transfer complete !\n");//数据包传输完成

                    upload_update_pack_down_status(0x00);//完成
                    deal_update(NULL,0);//因为app没有给我执行升级的命令，，这里手动执行升级
                }
                else
                {
                    updata_pack.cur_packet_index++;//直接判定请问下一个包
                    printf("request next pack index:%d \n",updata_pack.cur_packet_index);
                    request_update_pack_send(updata_pack.cur_packet_index);
                }
            }
            else
            {
                printf("request pack is %d ,but get is %d \n",updata_pack.cur_packet_index,((uint16_t)(pack[5]<<8)+pack[6]));
            }
//#ifndef UPDATE_TEST
        }
        else
        {

            printf("request pack length is error,cur len %d,index %d\n ",(_length-9),updata_pack.cur_packet_index);
            request_update_pack_send(updata_pack.cur_packet_index);
        }
//#endif
    }
    else
    {
        printf("request pack pos[4] is != 0 !\n ");
    }

    return 0;
}
#include "usart_protocol_subset_update.h"
static uint8_t deal_update(uint8_t * pack,uint16_t _length) //执行升级
{
    printf("received a  deal update  pack (write size %d,check %d). ! \n",updata_pack.cur_write_size,g_check_value);
    uint8_t ack_pack[50];
    /*给与执行升级反馈*/
    uint8_t result=0;
    uint16_t length_tmp= SetUpdatePacket(DEAL_UPDATE,1,&result,ack_pack);
    data_send((uint8_t *)ack_pack,length_tmp);

    if(curr_update_dev_type==DEVICE_TYPE) {
        printf("deal_update gateway\n");
        update_end(updata_pack.cur_write_size,g_check_value);		//重启开始烧录

    } else {
        printf("deal_update subset\n");
        usart_get_subset_soft_version();
    }

}

uint8_t upload_update_result(uint8_t result)
{
    printf("upload updata result %x \n", result);
    uint8_t ack_pack[50] = {0};
    uint8_t sendBuf[17] = {0};
    sendBuf[0] = result;
    memset(sendBuf, 0, sizeof(sendBuf));
    memcpy(sendBuf + 1, SOFTWARE_VER, strlen(SOFTWARE_VER));

    uint16_t length_tmp = SetUpdatePacket(UPLOAD_UPDATE_RESULT, 17, sendBuf, ack_pack);
    data_send((uint8_t *)ack_pack, length_tmp);
    return 0;
}
